/*global pi, RefResource */
// 时间线模块，提供对数值进行线性插值或Hermite Curve插值，提供对单个或多个域的求值

pi.mod.define('pi.timeline', function (pi) {
	"use strict";
	// 定义模块
	var module = {},
		// 获得指定对象的key，key如果是数组，则返回值的数组
		get = function (obj, key) {
			var i, arr;
			if (pi.lang.isArray(key)) {
				i = key.length;
				arr = [];
				arr.length = i;
				for (i = i - 1; i >= 0; i--) {
					arr[i] = obj[key[i]];
				}
				return arr;
			}
			return obj[key];
		},
		// 线性计算插值
		interLinear = function (obj1, obj2, key, f) {
			var i, arr, v1;
			if (pi.lang.isArray(key)) {
				i = key.length;
				arr = [];
				arr.length = i;
				for (i = i - 1; i >= 0; i--) {
					v1 = obj1[key[i]];
					arr[i] = v1 + (obj2[key[i]] - v1) * f;
				}
				return arr;
			}
			v1 = obj1[key];
			return v1 + (obj2[key] - v1) * f;
		},
		// 插值Catmull-Rom样条
		interCatmullRom = function (x1, x2, x3, x4, weight, t, t2, t3) {
			var p0 = 2 * x2,
				p1 = x3 - x1,
				p2 = 2 * x1 - 5 * x2 + 4 * x3 - x4,
				p3 = x4 - x1 + 3 * x2 - 3 * x3;
			return weight * (p0 + p1 * t + p2 * t2 + p3 * t3);
		},
		// 插值三次厄尔密样条，假设一条过v1、v2、v3、v4点的平滑曲线，求其在t上的点，t范围是0到1
		interHermite = function (v1, v2, v3, v4, key, weight, t) {
			var i, arr, k, t2 = t * t,
				t3 = t * t2;
			if (pi.lang.isArray(v1)) {
				i = key.length;
				arr = [];
				arr.length = i;
				for (i = i - 1; i >= 0; i--) {
					k = key[i];
					arr[i] = interCatmullRom(v1[k], v2[k], v3[k], v4[k], weight, t, t2, t3);
				}
				return arr;
			}
			return interCatmullRom(v1[key], v2[key], v3[key], v4[key], weight, t, t2, t3);
		},
		// 获得时间所在的时间数组中的位置
		index = function (array, starttime, currenttime, one) {
			var i, n = array.length,
				t = array.totaltime,
				time = currenttime - starttime;
			if (t === undefined) {
				t = 0;
				for (i = 0; i < n; i++) {
					t += array[i].time;
				}
				array.totaltime = t;
			}
			if (time > t) {
				if (one) {
					return {
						index: n - 1,
						time: t - time,
						over: true
					};
				}
				time = time % t;
			}
			for (i = 0; i < n; i++) {
				t = array[i].time;
				if (time < t) {
					break;
				}
				time -= t;
			}
			return {
				index: i,
				time: time
			};
		};

	// 线性求值
	module.linear = function (key, array, starttime, currenttime, one) {
		var n = array.length,
			it = index(array, starttime, currenttime, one),
			i = it.index,
			v = array[i];
		if (it.over || it.time === 0 || n === 1) {
			return {over: it.over, v: get(v, key)};
		}
		return {over: false, v: interLinear(v, array[(i + 1 === n) ? 0 : i + 1], key, it.time / v.time)};
	};
	// 曲线平滑求值
	module.curve = function (key, array, starttime, currenttime, one, weight) {
		var t, v2, v3, v4, n = array.length,
			it = index(array, starttime, currenttime, one),
			i = it.index,
			v = array[i];
		if (it.over || it.time === 0 || n === 1) {
			return get(v, key);
		}
		if (n === 2) {
			return interLinear(v, array[(i === 1) ? 0 : i + 1], key, it.time / v.time);
		}
		if (i === 0) {
			// 处理端点的情况
			v2 = v;
			v3 = array[1];
			v4 = array[2];
			if (one) {
				//不受末端的影响
				t = v.time + v3.time + v4.time;
			} else {
				v = array[n - 1];
				t = v.time + v2.time + v3.time + v4.time;
				it.time += v.time;
			}
		} else if (i < n - 2) {
			v2 = v;
			v = array[i - 1];
			v3 = array[i + 1];
			v4 = array[i + 2];
			t = v.time + v2.time + v3.time + v4.time;
			it.time += v.time;
		} else if (i === n - 2) {
			v2 = v;
			v = array[i - 1];
			v3 = array[i + 1];
			if (one) {
				//不受起点的影响
				v4 = v3;
				t = v.time + v2.time + v3.time;
			} else {
				v4 = array[0];
				t = v.time + v2.time + v3.time + v4.time;
			}
			it.time += v.time;
		} else if (i === n - 1) {
			if (one) {
				return interLinear(v, array[0], key, it.time / v.time);
			}
			v2 = v;
			v = array[i - 1];
			v3 = array[0];
			v4 = array[1];
			t = v.time + v2.time + v3.time + v4.time;
			it.time += v.time;
		}
		return interHermite(v, v2, v3, v4, key, weight, it.time / t);
	};
	module.index = index;

	return module;
});